/**
 * Copyright &copy; 2016-2017 <a href="http://git.oschina.net/whoamien/backend_management">Backend Management</a> All rights reserved.
 */
package com.xw.app.generator.controller;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Maps;
import com.xw.app.generator.service.CodeGeneratorService;
import com.xw.app.generator.vo.Column;
import com.xw.app.generator.vo.GeneratorSelection;
import com.xw.app.generator.vo.Table;
import com.xw.app.service.SysDictService;
import com.xw.app.vo.CodeGenerateResult;
import com.xw.framework.base.controller.BaseSpringController;
import com.xw.util.DateUtil;
import com.xw.util.ZipUtil;

/**
 * The Class CodeGeneratorController.
 *
 * @author Xi Wei
 */
@RequestMapping("/codeGenerator")
@SessionAttributes("generatorSelection")
@Controller
public class CodeGeneratorController extends BaseSpringController {

	@Autowired
	private CodeGeneratorService codeGeneratorService;
	@Autowired
	private SysDictService sysDictService;
	
	@Value("${error.CodeGenerator.partialsucceed}")
	private String partialSucceedMessage;
	@Value("${error.CodeGenerator.succeed}")
	private String succeedMessage;
	
	/**
	 * 第一步：进入代码生成器列表页面.
	 *
	 * @param generatorSelection the generator selection
	 * @return the model and view
	 */
	@RequestMapping(value={"","/","/listTables"})
	public ModelAndView listTables(GeneratorSelection generatorSelection){
		ModelAndView result = new ModelAndView("/CodeGenerator/selectTable");
		List<Table> tableList = codeGeneratorService.listTables();
		ModelMap map = new ModelMap();
		map.addAttribute("tableList", tableList);
		map.addAttribute("generatorSelect", generatorSelection);
		result.addAllObjects(map);
		return result;		
	}
	
	/**
	 * 第二步：根据选中的表获取所有字段，选择使用数据字典的字段.
	 *
	 * @param generatorSelection the generator selection
	 * @param request the request
	 * @return the model and view
	 */
	@RequestMapping("/listColumnsForDataDict")
	public ModelAndView listColumnsForDataDict(GeneratorSelection generatorSelection,HttpServletRequest request){
		String[] items = request.getParameterValues("tableNames");
		Map<String,List<Column>> columnMap = Maps.newLinkedHashMap();
		ModelAndView result = new ModelAndView("/CodeGenerator/specifyDataDict");
		
		for(String item : items){
			//List<Columns> columnList = codeGeneratorService.listColumns(item);
			Table table = codeGeneratorService.getTable(item,true);
			columnMap.put(item, table.getColumnList());
		}
		ModelMap map = new ModelMap();
		map.addAttribute("columnMap", columnMap);
		map.addAttribute("dataDictList", sysDictService.getAllParentDict());
		map.addAttribute("generatorSelect", generatorSelection);
		result.addAllObjects(map);
		return result;				
	}
	
	/**
	 * 第三步：列出所有的外键信息，选择该外键在页面显示的字段.
	 *
	 * @param generatorSelection the generator selection
	 * @param request the request
	 * @return the model and view
	 */
	@RequestMapping("/listForeignKeys")
	public ModelAndView listForeignKeys(GeneratorSelection generatorSelection,HttpServletRequest request){
		Map<String,Table> columnMap = Maps.newLinkedHashMap();
		ModelAndView result = new ModelAndView("/CodeGenerator/specifyForeignKey");
		
		for(String item : generatorSelection.getTableNames()){
			//List<Columns> columnList = codeGeneratorService.listColumns(item);
			Table table = codeGeneratorService.getTable(item,true);
			columnMap.put(item, table);
		}
		ModelMap map = new ModelMap();
		map.addAttribute("columnMap", columnMap);
		map.addAttribute("generatorSelect", generatorSelection);
		result.addAllObjects(map);
		return result;				
	}

	
	/**
	 * List columns.
	 *
	 * @param generatorSelection the generator selection
	 * @param request the request
	 * @return the model and view
	 */
	@RequestMapping("/listColumns")
	public ModelAndView listColumns(GeneratorSelection generatorSelection,HttpServletRequest request){
		String[] items = request.getParameterValues("tableNames");
		Map<String,List<Column>> columnMap = Maps.newLinkedHashMap();
		ModelAndView result = new ModelAndView("/CodeGenerator/confirmColumns");
		
		for(String item : items){
			List<Column> columnList = codeGeneratorService.listColumns(item);
			columnMap.put(item, columnList);
		}
		ModelMap map = new ModelMap();
		map.addAttribute("columnMap", columnMap);
		result.addAllObjects(map);
		return result;				
	}
	
	/**
	 * 第四步：根据选择生成代码.
	 *
	 * @param generatorSelection the generator selection
	 * @param request the request
	 * @param status the status
	 * @param redirectAttributes the redirect attributes
	 * @return the model and view
	 */
	@RequestMapping("/generate")
	public ModelAndView generate(GeneratorSelection generatorSelection,HttpServletRequest request,SessionStatus status,RedirectAttributes redirectAttributes){
		generatorSelection.setTemplateFolder(request.getSession().getServletContext().getRealPath(""));
		CodeGenerateResult result = codeGeneratorService.generate(generatorSelection);
		status.setComplete();
		if(result == null){
			addErrorKey(redirectAttributes, "error.CodeGenerator.failed");
		}else if(!result.getExceptionTraceList().isEmpty()){
			String traceName = saveExceptionTrace(result, request);
			String zipName = zipSucessfile(result, request);
			addError(redirectAttributes, MessageFormat.format(partialSucceedMessage, request.getContextPath()+"/upload/"+zipName,request.getContextPath()+"/upload/"+traceName));
			
		}else{
			String zipName = zipSucessfile(result, request);
			addMessage(redirectAttributes,MessageFormat.format(succeedMessage, request.getContextPath()+"/upload/"+zipName));
		}
		
		return new ModelAndView("redirect:/codeGenerator");
	}
	
	private String zipSucessfile(CodeGenerateResult result,HttpServletRequest request){
		try {
			String successFile = request.getSession().getServletContext().getRealPath("upload") + File.separator + "code.zip";
			File file = new File(successFile);
			file.delete();
			ZipUtil.zipFile(result.getOutputFolder(),successFile);
			//FileUtils.moveFile(new File(zipFileName), file);
			return file.getName();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		
	}
	
	private String saveExceptionTrace(CodeGenerateResult result,HttpServletRequest request){
		String exceptionFile = request.getSession().getServletContext().getRealPath("upload") + File.separator + "CodeGeneratorFailMessage_"+DateUtil.parseDate(DateUtil.getSystemTimestamp(), "yyyyMMddHHmmss") + ".txt";
		File file = new File(exceptionFile);
		try {
			
			file.delete();
			if(!file.exists()){
				file.createNewFile();
			}
			result.getExceptionTraceList().forEach(x -> {
				try {
					FileUtils.writeStringToFile(file, x, true);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			});
			result.getExceptionFileList().forEach(x -> {
				try {
					new File(result.getOutputFolder() + File.separator + x).delete();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			});
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		return file.getName();
	}
}
